<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // 封装函数 把return 的各种情况写在一个函数里 复用性
    function resolvePromise(x,p2,resolve,reject){
        if(x===p2){
                            throw new TypeError('Chaining cycle detected for promise #<Promise>')
                        }
                        if(x instanceof HMPromise){
                            x.then(res=>resolve(res),res=>reject(res))
                        }else{
                            resolve(x)//说明p2也是FULFILLED状态
                        }
    }
    // 封装一个异步任务的函数
        // 1.定义函数
        // 2.调用核心api 3.使用
    function runAsynctask(callback){
        if( typeof queueMicrotask==='function'){
            queueMicrotask(callback)
        }else if(typeof MutationObserver==='function'){
            const obs=new MutationObserver(callback)
            const divNode=document.createElement('div')
            obs.observe(divNode,{childList:true})
            divNode.innerText='itheima666'
        }else{
            setTimeout(callback,0)
        }
    }

        // 1、创建一个新的Promise构造函数
    // 构造函数 
    const FULFILLED='fulfilled'
    const PENDING='pending'
    const REJECT='reject'
    class HMPromise{
        state=PENDING
        result=undefined
        #handle=[]//数组包括回调成功和不成功
        constructor(func){
          const  resolve=(result)=>{
            if(this.state===PENDING){
                this.state=FULFILLED
                this.result=result
                this.#handle.forEach(({onFulfilled})=>onFulfilled(this.result))
            }
           
            }
            const reject=(result)=>{
                if(this.state===PENDING){
                this.state=REJECT
                this.result=result
                this.#handle.forEach(({onRejected})=>onRejected(this.result))

            }

            }
            

            try {
                func(resolve,reject)//传的参数是函数
            } catch (error) {
                reject(error)
            }
        }
       

        // 2、添加实例方法then
          // 异步及多次调用 保存回调函数至私密属性，当state变了再执行
          // 链式调用-1、添加新的实例2、获取返回值---1.处理返回值 2.处理异常 3.处理返回promise 4.处理重复引用
      then(onFulfilled, onRejected){
        onFulfilled= typeof onFulfilled ==='function'?onFulfilled:x=>x
        onRejected=typeof onRejected==='function'?onRejected:x => { throw x; }
        
        const p2=new HMPromise((resolve,reject)=>{
            if(this.state===FULFILLED){//把这些放到p2中是不影响其对实例p的影响，因为new的时候也是立刻执行的，放在外面和里面没有区别
                    runAsynctask(()=>{
                      
                    // 当p是FULFILLED状态时
                    try{
                        const x=  onFulfilled(this.result)
                        resolvePromise(x,p2,resolve,reject)
                    }catch(error){
                        reject(error)//说明p2是rejected状态
                    }

                    })
                }else if(this.state===REJECT){
                    runAsynctask(()=>{
                    

                        try {
                            const x=onRejected(this.result)
                            resolvePromise(x,p2,resolve,reject)
                        } catch (error) {
                            reject(error)
                        }


                    })
                }else if(this.state===PENDING){
                    this.#handle.push({
                        onFulfilled:()=>{
                            runAsynctask(()=>{
                                try {
                               const x=onFulfilled(this.result)
                                    resolvePromise(x,p2,resolve,reject)
                                } catch (error) {
                                    reject(error)
                                }

                        
                    })
                        },onRejected:()=>{
                            runAsynctask(()=>{
                                try {
                                const x=onRejected(this.result)    
                                    resolvePromise(x,p2,resolve,reject)
                                } catch (error) {
                                    reject(error)
                                }
                        
                            })
                        }    
                    })
                }
        })
              

                return p2
             }
            //  catch 
             catch(onRejected){
                return this.then(undefined,onRejected)

}
            finally(onFinally){//不管是成功与否，都会实现
                return this.then(onFinally,onFinally)
            }

            static resolve(value){
            if(value instanceof HMPromise ){
                return value
            }
            return new HMPromise((resolve,reject)=>{
                resolve(value)
            })
        }
    }
        
// 测试1

const p=new HMPromise((resolve,reject)=>{
    // resolve('哈哈')
   
    resolve('哈哈')
//   throw 'error2'
    // reject('呜呜')
})
let p3=HMPromise.resolve(p)
console.log(p3);//HMPromise {state: 'fulfilled', result: 2, #handle: Array(0)}


// p.then(res=>{
//     console.log(res,'成功');
// }).catch(error=>{console.log("error:",error)})
// .finally(res=>console.log('finally'))
 

// 测试重复调用
// const p2=p.then(res=>{
//     return p2
// })
// p2.then(res=>{
// },error=>{
//     console.log('有问题',error);
// })


// 测试返回的promise
// p.then(res=>{
//     console.log("p",'哈哈');
//     // throw 'error2'
//     return new HMPromise((resolve,reject)=>{
//         // resolve(11)
//         reject('error')
//     })
// }).then(res=>{
//     console.log("p2",res);
// },res=>{
//     console.log('p2',res);
// })
// p:HMPromise {state: 'fulfilled', result: '哈哈'}

// -----------测试2 异步--------------------------------
//异步任务1 queueMicrotask
// console.log(1);
// queueMicrotask(()=>{
//     console.log('queueMicrotask');
// })
// console.log(2);

// 异步任务2 Mu
// console.log('开始');
// // 1.创建观察期，并传入回调函数
// const obs=new MutationObserver(()=>{
//     console.log('MutationObserver');
// })
// // 2.创建元素，并添加监听
// const divNode=document.createElement('div')
// // 参数一 观察的dom节点;参数二 观察的选项（childList 观察子节点改变）
// obs.observe(divNode,{childList:true})
// // 3、修改元素内容
// divNode.innerText='itheima 666'
// console.log('结束');



    </script>
</body>
</html>